﻿using Coolzon.Common;
using Coolzon.Realtime.Contracts;
using Coolzon.Realtime.Contracts.CommandData;
using Coolzon.Realtime.ServerApp.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Coolzon.Realtime.ServerApp.ServiceImplement
{
    /// <summary>
    /// 重新连接，
    /// 
    /// </summary>
    public class ReqReconnectHandler : BaseHandler<ReqReconnectData, RespReconnectData>
    {
        private static object s_reconnectLockObj = new object();

        public ReqReconnectHandler()
            : base(SCENARIO.CONNECT, COMMAND.CONNECT.RECONNECT)
        {
        }

        /// <summary>
        /// 重新连接，如果是控制端，那么可以恢复域，如果不是控制端如果没有域那么不能重连成功
        /// 也就是在控制端重连进来之前，展示端不可能重连成功。
        /// </summary>
        /// <param name="request"></param>
        /// <param name="requestData"></param>
        /// <returns></returns>
        protected override RespReconnectData OnHandle(Request request, ReqReconnectData requestData)
        {
            Logger.WarningToTag("Handler", string.Format("请求重新连接,useridentity:{0},domainid:{1},solution:{2},operatorId:{3},AppType:{4}",
                requestData.UserIdentity,
                requestData.DomainId,
                requestData.SolutionName,
                requestData.OperatorIdentity, requestData.AppType));

            if (string.Equals(requestData.AppType, "CONSOLEAPP", StringComparison.CurrentCultureIgnoreCase))
            {
                //控制端类型
                if (requestData.OperatorIdentity == request.Header.UserIdentity)
                {
                    // 是操作员
                    return Reconnect4Operator(request, requestData);
                }
            }
            else if (string.IsNullOrWhiteSpace(request.Header.DomainId))
            {
                //处理未进入域的非操作员重连
                return Reconnect4NoneDomain(request, requestData);
            }

            // 非操作员重连，如果没有域视为失败
            return Reconnect4NoneOperator(request, requestData);
        }

        /// <summary>
        /// 处理未进入域的非操作员重连
        /// </summary>
        /// <param name="request"></param>
        /// <param name="requestData"></param>
        /// <returns></returns>
        private RespReconnectData Reconnect4NoneDomain(Request request, ReqReconnectData requestData)
        {
            RespReconnectData responseData = new RespReconnectData();
            responseData.ServerIP = Config.Current.IP;
            responseData.ServerPort = Config.Current.Port;

            Client client = ServerData.Instance.GetClient(requestData.UserIdentity);
            if (client == null)
            {
                #region 用户不存在在内存里
                // 用户不存在于服务器的客户单列表中，这种情况主要是由于服务器重新启动导致
                // 从服务器上创建用户对象，然后添加到服务器的客户端列表中
                client = new Client();
                client.UserIdentity = requestData.UserIdentity;
                client.UserAccount = requestData.UserAccount;
                client.AppType = requestData.AppType;
                // 设置客户端的最后活跃时间
                // 否则将会在并发的重连接中被下一个终端个移除掉
                client.LatestActiveTicks = DateTime.Now.Ticks;
                // 设置终端的控制状态
                if (requestData.ControlState == ControlState.UnderControl)
                {
                    client.ControlState = ControlState.UnderControl;
                }
                else
                {
                    client.ControlState = ControlState.OutOfControl;
                }

                if (ServerData.Instance.AddClient(client))
                {
                    // 设置控制端的状态为正在重新连接
                    client.State = ClientState.InDomain;
                    // 获取控制端的回调接口实例
                    client.Callback = System.ServiceModel.OperationContext.Current.GetCallbackChannel<IMainServiceCallback>();

                    responseData.IsSuccess = true;
                }
                else
                {
                    // 添加用户到服务器列表出错，服务器的客户端列表已满
                    responseData.IsSuccess = false;
                    responseData.Message = "重连失败,服务器中的客户端数量已满";
                    client = null;
                }
                #endregion
            }
            else
            {
                client.LatestActiveTicks = DateTime.Now.Ticks;
                client.Callback = System.ServiceModel.OperationContext.Current.GetCallbackChannel<IMainServiceCallback>();
                responseData.IsSuccess = true;
            }
            return responseData;
        }


        /// <summary>
        /// 操作员重连
        /// 域不存在，创建域
        /// 加入域设置为操作员
        /// </summary>
        /// <param name="request"></param>
        /// <param name="requestData"></param>
        /// <returns></returns>
        private RespReconnectData Reconnect4Operator(Request request, ReqReconnectData requestData)
        {
            RespReconnectData responseData = new RespReconnectData();

            // 获取用户所要创建的域的方案的，域实例模型
            byte domainInstanceMode = DomainInstanceMode.Singleton;

            if (domainInstanceMode == DomainInstanceMode.Singleton)
            {
                SingletonModeReconnectStrategy strategy = new SingletonModeReconnectStrategy();

                responseData = strategy.Reconnect4Operator(request, requestData);
            }
            return responseData;
        }

        /// <summary>
        /// 非操作员重连,首先域要存在，然后判断操作员是否存在，不存在则返回重连失败
        /// 然后创建客户端或更新客户端
        /// 如果此服务器是主服务并且方案不同，则通知client更新方案，重连状态为false
        /// 方案相同则返回ViewState，重连成功
        /// </summary>
        /// <param name="request"></param>
        /// <param name="requestData"></param>
        /// <returns></returns>
        private RespReconnectData Reconnect4NoneOperator(Request request, ReqReconnectData requestData)
        {
            RespReconnectData responseData = new RespReconnectData();

            // 获取用户所要创建的域的方案的，域实例模型
            byte domainInstanceMode = DomainInstanceMode.Singleton;

            if (domainInstanceMode == DomainInstanceMode.Singleton)
            {
                SingletonModeReconnectStrategy strategy = new SingletonModeReconnectStrategy();

                responseData = strategy.Reconnect4NoneOperator(request, requestData);
            }
            return responseData;
        }
    }
}
